package com.gcloud.mesh.analysis.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import org.jeecg.common.exception.ParamException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.gcloud.framework.db.PageResult;
import com.gcloud.mesh.analysis.dao.DemoDao;
import com.gcloud.mesh.analysis.dao.FitterDao;
import com.gcloud.mesh.analysis.dao.SimulateDao;
import com.gcloud.mesh.analysis.data.IDataCleaning;
import com.gcloud.mesh.analysis.data.PolynomialDataCleaning;
import com.gcloud.mesh.analysis.entity.DemoEntity;
import com.gcloud.mesh.analysis.entity.FitterEntity;
import com.gcloud.mesh.analysis.entity.SimulateEntity;
import com.gcloud.mesh.analysis.enums.AlgorithmType;
import com.gcloud.mesh.analysis.enums.ChartType;
import com.gcloud.mesh.analysis.enums.MeterXType;
import com.gcloud.mesh.analysis.enums.MeterYType;
import com.gcloud.mesh.analysis.ml.PolynomialModelFitter;
import com.gcloud.mesh.analysis.service.IDataCleaningService;
import com.gcloud.mesh.analysis.service.IIntelligentDeviceService;
import com.gcloud.mesh.analysis.utils.FitterUtil;
import com.gcloud.mesh.asset.enums.DeviceType;
import com.gcloud.mesh.asset.service.IAssetService;
import com.gcloud.mesh.header.exception.AnalysisErrorCode;
import com.gcloud.mesh.header.exception.BaseException;
import com.gcloud.mesh.header.msg.analysis.CreateFitterMsg;
import com.gcloud.mesh.header.msg.analysis.CreateSimulateMsg;
import com.gcloud.mesh.header.msg.analysis.DoFitterMsg;
import com.gcloud.mesh.header.msg.analysis.DoSimulateMsg;
import com.gcloud.mesh.header.msg.analysis.ListOptimumMsg;
import com.gcloud.mesh.header.msg.analysis.ListSimulateMsg;
import com.gcloud.mesh.header.msg.analysis.OptimumMsg;
import com.gcloud.mesh.header.msg.analysis.UpdateFitterMsg;
import com.gcloud.mesh.header.msg.analysis.UpdateSimulateMsg;
import com.gcloud.mesh.header.vo.analysis.AirFitterVo;
import com.gcloud.mesh.header.vo.analysis.ChartVo;
import com.gcloud.mesh.header.vo.analysis.DataVo;
import com.gcloud.mesh.header.vo.analysis.FitterVo;
import com.gcloud.mesh.header.vo.analysis.NodeFitterVo;
import com.gcloud.mesh.header.vo.analysis.NodeHistoryVo;
import com.gcloud.mesh.header.vo.analysis.NodeSimulateVo;
import com.gcloud.mesh.header.vo.analysis.OptimumVo;
import com.gcloud.mesh.header.vo.analysis.SimulateVo;
import com.gcloud.mesh.header.vo.asset.DeviceItemVo;
import com.gcloud.mesh.header.vo.asset.NodeItemVo;
import com.gcloud.mesh.utils.MeshMathUtil;
import com.gcloud.mesh.utils.TimestampUtil;
import com.google.protobuf.Timestamp;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class IntelligentDeviceServiceImpl implements IIntelligentDeviceService {
	
	@Autowired
	private IAssetService assetService;
	
	@Autowired
	private IDataCleaningService dataCleaningService;
	
	@Autowired
	private PolynomialModelFitter polynomial;
	
	@Autowired
	private FitterDao fitterDao;
	
	@Autowired
	private SimulateDao simulateDao;
	
	@Autowired
	private DemoDao demoDao;
	
	@Value("${mesh.analysis.enable:false}")
	private boolean demoEnable;

	@Override
	public String createFitter(CreateFitterMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getNodeId() != null) {
			props.put("node_id", msg.getNodeId());
		}
		if(msg.getAirId() != null) {
			props.put("air_id", msg.getAirId());
		}
		FitterEntity fitter = fitterDao.findUniqueByProperties(props);
		if(fitter != null) {
			log.error("[IntelligentDeviceService][createFitter] node_id={}， air_id={}对应的资源已存在", msg.getNodeId(), msg.getAirId());
			throw new BaseException(AnalysisErrorCode.RESOURCE_ALREADY_EXISTS);
		} 
		fitter = new FitterEntity();
		fitter.setId(UUID.randomUUID().toString());
		fitter.setNodeId(msg.getNodeId());
		fitter.setAirId(msg.getAirId());
		fitter.setMetricX(msg.getMetricX());
		fitter.setMetricY(msg.getMetricY());
		fitter.setAlgorithm(AlgorithmType.POLYNOMIAL.getName());
		fitter.setDegree(msg.getDegree());
		try {
			fitterDao.save(fitter);
		} catch (Exception e) {
			log.error("[IntelligentDeviceService][createFitter] 数据保存异常: {}", e.getMessage());
			throw new BaseException(AnalysisErrorCode.DATABASE_SAVE_ERROR);
		}
		
		return fitter.getId();
	}

	@Override
	public FitterVo doFitter(DoFitterMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		//默认degree = 2
		msg.setDegree(4);
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getNodeId() != null) {
			props.put("node_id", msg.getNodeId());
		}
		if(msg.getAirId() != null) {
			props.put("air_id", msg.getAirId());
		}
		FitterEntity fitter = fitterDao.findUniqueByProperties(props);
			
		// polynomial fitter train
		List<ChartVo> charts = new ArrayList<ChartVo>();
		PolynomialDataCleaning data = null;
		Date startTime = msg.getStartTime();
		Date endTime = msg.getEndTime();
		try {
			data = (PolynomialDataCleaning) dataCleaningService.acquireFitterData(startTime, endTime, msg.getNodeId(), msg.getAirId());
		} catch(Exception e) {
			log.error("[IntelligentDeviceService][doFitter] DataCleaningService的acquireFitterData方法访问异常: {}", e.getMessage());
			throw new BaseException(AnalysisErrorCode.DATACLEANING_SERVICE_ERROR);
		}

//		if(!demoEnable) {
//			Date startTime = msg.getStartTime();
//			Date endTime = msg.getEndTime();
//			try {
//				data = (PolynomialDataCleaning) dataCleaningService.acquireFitterData(startTime, endTime, msg.getNodeId(), msg.getAirId());
//			} catch(Exception e) {
//				log.error("[IntelligentDeviceService][doFitter] DataCleaningService的acquireFitterData方法访问异常: {}", e.getMessage());
//				throw new BaseException(AnalysisErrorCode.DATACLEANING_SERVICE_ERROR);
//			}
//		}else {
////			data = (PolynomialDataCleaning) getDemoData("fitter", msg.getStartTime(), msg.getEndTime());
//			data = (PolynomialDataCleaning) getDemoData("fitter", msg.getNodeId(), msg.getAirId(), msg.getStartTime(), msg.getEndTime());
//			
//		}
		
		double[] factors = polynomial.train(data, msg.getDegree());
		FitterVo reply = new FitterVo();
		
		ChartVo scatter = new ChartVo();
		scatter.setXLabel(MeterXType.SERVER_POWER_CONSUMPTION.getCnName());
		scatter.setYLabel(MeterXType.AIR_OUT_TEMP.getCnName());
		scatter.setType(ChartType.SCATTER.getName());
//		sorted(data.getData());
		scatter.setData(data.getData());
		ChartVo line = new ChartVo();
		line.setXLabel(MeterXType.SERVER_POWER_CONSUMPTION.getCnName());
		line.setYLabel(MeterXType.AIR_OUT_TEMP.getCnName());
		line.setType(ChartType.LINE.getName());
		List<DataVo> lineData = getDataFitter(factors, data.getData());
		sorted(lineData);
		line.setData(lineData);
		charts.add(scatter);
		charts.add(line);
	
		if(!demoEnable) {
			String result = FitterUtil.calcFitterMode(factors);		
			if(fitter == null) {
				//新增
				fitter = new FitterEntity();
				fitter.setId(UUID.randomUUID().toString());
				fitter.setNodeId(msg.getNodeId());
				fitter.setAirId(msg.getAirId());
				fitter.setMetricX(MeterXType.AIR_OUT_TEMP.getName());
				fitter.setMetricY(MeterYType.SERVER_POWER_CONSUMPTION.getName());
				fitter.setAlgorithm(AlgorithmType.POLYNOMIAL.getName());
				fitter.setDegree(msg.getDegree());
				fitter.setResult(result);
				fitter.setStartTime(msg.getStartTime());
				fitter.setEndTime(msg.getEndTime());
				try {
					fitterDao.save(fitter);
				} catch (Exception e) {
					log.error("[IntelligentDeviceService][doFitter] 数据保存异常: {}", e.getMessage());
					throw new BaseException(AnalysisErrorCode.DATABASE_SAVE_ERROR);
				}
			} else {
				List<String> updates = new ArrayList<String>();
				if(msg.getDegree() != null) {
					updates.add("degree");
					fitter.setDegree(msg.getDegree());
				}
				if(msg.getStartTime() != null) {
					updates.add("start_time");
					fitter.setStartTime(msg.getStartTime());
				}
				if(msg.getEndTime() != null) {
					updates.add("end_time");
					fitter.setEndTime(msg.getEndTime());
				}
				updates.add("result");
				fitter.setResult(result);
				updates.add("update_time");
				fitter.setUpdateTime(new Date());
				try {
					fitterDao.update(fitter, updates);
				}catch(Exception e) {
					log.error("[IntelligentDeviceService][doFitter] 数据更新异常: {}", e.getMessage());
					throw new BaseException(AnalysisErrorCode.DATABASE_UPDATE_ERROR);
				}
				
			}
		}else {
			if(fitter == null) {
				fitter = saveFitter(msg);
			} else {
				updateFitter(msg, fitter);
			}
		}
		reply.setDegree(fitter.getDegree());
		reply.setCharts(charts);
		return reply;
	}

	@Override
	public String updateFitter(UpdateFitterMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public FitterVo detailFitter(String id, String userId) throws BaseException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public PageResult<NodeFitterVo> pageNodeFitter(int pageNum, int pageSize, String datacenterId, String name, String userId)
			throws BaseException {
		// TODO Auto-generated method stub
		PageResult<NodeItemVo> nodes = null;
		try {
			nodes = assetService.pageNode(pageNum, pageSize, datacenterId, name, null, userId);
		}catch(Exception e) {
			log.info("[IntelligentDeviceService][pageNodeFitter] assetService的pageNode方法访问异常: {}", e.getMessage());
		}
		PageResult<NodeFitterVo> result = new PageResult<NodeFitterVo>();
		List<NodeFitterVo> nodeFitters = new ArrayList<NodeFitterVo>();
		if(nodes != null) {
			for(NodeItemVo nodeVo: nodes.getList()) {
				NodeFitterVo fitter = new NodeFitterVo();
				fitter.setName(nodeVo.getName());
				fitter.setId(nodeVo.getId());
				fitter.setDatacenterId(nodeVo.getDatacenterId());
				fitter.setRegion(nodeVo.getDatacenterName());
				fitter.setIpmiIp(nodeVo.getIpmiIp());
				fitter.setMgmIp(nodeVo.getMgmIp());
				fitter.setPowerStatus(nodeVo.getPowerStatus());
				fitter.setPowerStatusCnName(nodeVo.getPowerStatusCnName());
				
				try {
					fitter.setPowerConsumption(dataCleaningService.getPwrNode(nodeVo.getId()));
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageNodeFitter] DataCleaningService的getPwrNode方法访问异常: {}", e.getMessage());
				}
				
				nodeFitters.add(fitter);
			}
		}
		
		result.setList(nodeFitters);
		result.setPageNo(pageNum);
		result.setPageSize(pageSize);
		if(nodes != null) {
			result.setTotalCount(nodes.getTotalCount());
		}
		
		return result;
	}

	@Override
	public PageResult<AirFitterVo> pageAirFitter(int pageNum, int pageSize, String datacenterId, String name, String userId)
			throws BaseException {
		// TODO Auto-generated method stub
		PageResult<DeviceItemVo> airs = null;
		try {
			airs = assetService.pageDevice(pageNum, pageSize, datacenterId, DeviceType.AIR_CONDITION.getNo(), name, userId);
		}catch(Exception e) {
			log.info("[IntelligentDeviceService][pageAirFitter] assetService的pageDevice方法访问异常: {}", e.getMessage());
		}
		
		PageResult<AirFitterVo> result = new PageResult<AirFitterVo>();
		List<AirFitterVo> airFitters = new ArrayList<AirFitterVo>();
		
		if(airs != null) {
			for(DeviceItemVo deviceVo: airs.getList()) {
				AirFitterVo fitter = new AirFitterVo();
				fitter.setName(deviceVo.getName());
				fitter.setId(deviceVo.getId());
				fitter.setDatacenterId(deviceVo.getDatacenterId());
				fitter.setRegion(deviceVo.getDatacenterName());
				try {
					fitter.setCurrentTemp(dataCleaningService.getAirCurrentTemp(deviceVo.getId()));
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageAirFitter] DataCleaningService的getAirCurrentTemp方法访问异常: {}", e.getMessage());
				}
				try {
					fitter.setSetTemp(dataCleaningService.getAirSetTemp(deviceVo.getId()));			
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageAirFitter] DataCleaningService的getAirSetTemp方法访问异常: {}", e.getMessage());
				}
				try {
					fitter.setSupplyAir(dataCleaningService.getAirOut(deviceVo.getId()));
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageAirFitter] DataCleaningService的getAirOut方法访问异常: {}", e.getMessage());
				}
				try {
					fitter.setReturnAir(dataCleaningService.getAirIn(deviceVo.getId()));
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageAirFitter] DataCleaningService的getAirIn方法访问异常: {}", e.getMessage());
				}
				
				airFitters.add(fitter);
			}
		}
		
		result.setList(airFitters);
		result.setPageNo(pageNum);
		result.setPageSize(pageSize);
		if(airs != null) {
			result.setTotalCount(airs.getTotalCount());
		}
		
		return result;
	}

	@Override
	public String deleteFitter(String id, String userId) throws BaseException {
		// TODO Auto-generated method stub
		FitterEntity fitter = fitterDao.getById(id);
		if(fitter == null) {
			log.error("[IntelligentDeviceService][createFitter] id={}对应的资源不存在", id);
			throw new ParamException(AnalysisErrorCode.RESOURCE_NOT_FOUND);
		}
		try {
			fitterDao.deleteById(id);
		} catch(Exception e) {
			log.error("[IntelligentDeviceService][deleteFitter] 资源 {} 删除失败", id);
			throw new BaseException(AnalysisErrorCode.DATEBASE_DELETE_ERROR);
		}
		
		return id;
	}

	@Override
	public String createSimulate(CreateSimulateMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getDatacenterId() != null) {
			props.put("datacenter_id", msg.getDatacenterId());
		}
		if(msg.getDeviceId() != null) {
			props.put("device_id", msg.getDeviceId());
		}
		SimulateEntity simulate = simulateDao.findUniqueByProperties(props);
		if(simulate != null) {
			log.error("[IntelligentDeviceService][createSimulate] datacenter_id={}， device_id={}对应的资源已存在", msg.getDatacenterId(), msg.getDeviceId());
			throw new BaseException(AnalysisErrorCode.RESOURCE_ALREADY_EXISTS);
		} 
		simulate = new SimulateEntity();
		simulate.setId(UUID.randomUUID().toString());
		simulate.setName(msg.getName());
		simulate.setDatacenterId(msg.getDatacenterId());
		simulate.setDeviceId(msg.getDeviceId());
		simulate.setDegree(2);
		simulate.setEnabled(true);
		simulate.setMetricX(MeterXType.SERVER_POWER_CONSUMPTION.getName());
		simulate.setStartTime(new Date());
		try {
			simulateDao.save(simulate);
		} catch (Exception e) {
			log.error("[IntelligentDeviceService][createSimulate] 数据保存异常: {}", e.getMessage());
			throw new BaseException(AnalysisErrorCode.DATABASE_SAVE_ERROR);
		}
		
		return simulate.getId();
	}

	@Override
	public SimulateVo doSimulate(DoSimulateMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getDatacenterId() != null) {
			props.put("datacenter_id", msg.getDatacenterId());
		}
		if(msg.getMetricX() != null) {
			props.put("metric_x", msg.getMetricX());
		}
		if(msg.getDeviceId() != null) {
			props.put("device_id", msg.getDeviceId());
		}
		if(MeterXType.getTypeByName(msg.getMetricX()) == null) {
			log.error("[IntelligentDeviceService][doSimulate] {}对应类型不支持", msg.getMetricX());
			throw new ParamException(AnalysisErrorCode.TYPE_NOT_FOUND);
		}
		if(msg.getDegree() > 4 || msg.getDegree() < 2) {
			throw new BaseException(AnalysisErrorCode.DEGREE_NOT_SUPPORT);
		}
		
		PolynomialDataCleaning data = null;
		double[] factors = null;
		
		try {
			data = (PolynomialDataCleaning) dataCleaningService.acquireSimulateData(msg.getStartTime(), msg.getEndTime(), msg.getDatacenterId(), msg.getDeviceId(), msg.getMetricX());
		} catch(Exception e) {
			log.error("[IntelligentDeviceService][doSimulate] DataCleaningService的acquireSimulateData方法访问异常: {}", e.getMessage());
			throw new BaseException(AnalysisErrorCode.DATACLEANING_SERVICE_ERROR);
		}
		SimulateEntity simulate = null;
		simulate = simulateDao.findUniqueByProperties(props);
		if(simulate == null) {
			simulate = saveSimulate(msg);
		} else {
//			updateSimulate(msg, simulate);
		}
		factors = polynomial.train(data, msg.getDegree());

//		try {
//			if(!demoEnable) {
//				data = (PolynomialDataCleaning) dataCleaningService.acquireSimulateData(msg.getStartTime(), msg.getEndTime(), msg.getDatacenterId(), msg.getDeviceId(), msg.getMetricX());
//			}else {
////				data = (PolynomialDataCleaning) getDemoData("simulate", msg.getStartTime(), msg.getEndTime());
//				data = (PolynomialDataCleaning) getDemoData("simulate", msg.getDeviceId(), msg.getStartTime(), msg.getEndTime());
//			}
//		} catch(Exception e) {
//			log.error("[IntelligentDeviceService][doSimulate] DataCleaningService的acquireSimulateData方法访问异常: {}", e.getMessage());
//			throw new BaseException(AnalysisErrorCode.DATACLEANING_SERVICE_ERROR);
//		}
		

//		SimulateEntity simulate = null;
//		simulate = simulateDao.findUniqueByProperties(props);
//		if(!demoEnable) {		
//			if(simulate == null) {
//				log.error("[IntelligentDeviceService][doSimulate] 仿真运行中");
//				throw new BaseException(AnalysisErrorCode.SIMULATE_RUNNING);
//			}
//			factors = FitterUtil.recalcFitterMode(simulate.getResult());
//		} else {	
//			if(simulate == null) {
//				simulate = saveSimulate(msg);
//			} else {
//				updateSimulate(msg, simulate);
//			}
//			factors = polynomial.train(data, msg.getDegree());
////			factors = getFactors();
//		}
		// polynomial simulate train

		SimulateVo reply = new SimulateVo();
		reply.setDegree(simulate.getDegree());
		List<ChartVo> charts = new ArrayList<ChartVo>();
		ChartVo scatter = new ChartVo();
		scatter.setXLabel(MeterXType.getTypeByName(msg.getMetricX()).getCnName());
		scatter.setYLabel(MeterYType.PUE.getCnName());
		scatter.setType(ChartType.SCATTER.getName());
		scatter.setData(data.getData());
		charts.add(scatter);
		ChartVo line = new ChartVo();
		line.setType(ChartType.LINE.getName());
		line.setXLabel(MeterXType.getTypeByName(msg.getMetricX()).getCnName());
		line.setYLabel(MeterYType.PUE.getCnName());
		List<DataVo> lineData = data.getData();
		simulateSorted(lineData);
//		autoAdapterFactors(msg.getDegree(), factors);
		line.setData(getDataFitter(factors, lineData));
	    charts.add(line);
	    reply.setCharts(charts);
		
		return reply;
	}

	@Override
	public String updateSimulate(UpdateSimulateMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public PageResult<SimulateVo> pageSimulate(int pageNum, int pageSize, String name, String userId)
			throws BaseException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String deleteSimulate(String id, String userId) throws BaseException {
		// TODO Auto-generated method stub
		SimulateEntity fitter = simulateDao.getById(id);
		if(fitter == null) {
			log.error("[IntelligentDeviceService][deleteSimulate] id={}对应的资源不存在", id);
			throw new ParamException(AnalysisErrorCode.RESOURCE_NOT_FOUND);
		}
		try {
			simulateDao.deleteById(id);
		} catch(Exception e) {
			log.error("[IntelligentDeviceService][deleteSimulate] 资源 {} 删除失败", id);
			throw new BaseException(AnalysisErrorCode.DATEBASE_DELETE_ERROR);
		}
		
		return id;
	}
	
	private double calcFitter(double[] factors, double x) {
		double result = 0;	
		if(factors.length == 6) {
			double c = factors[0];
			double a1 = factors[5];
			double a2 = factors[4];
			double a3 = factors[3];
			double a4 = factors[2];
			double a5 = factors[1];	
			result = a1*x*x*x*x*x + a2*x*x*x*x + a3*x*x*x + a4*x*x + a5*x + c;
		}	
		return result;
	}

	private List<DataVo> getDataFitter(double[] factors, double[] dataX) {
		List<DataVo> data = new ArrayList<DataVo>();
		for(int i=0; i<dataX.length; i++) {
			DataVo vo = new DataVo();
			vo.setDataX(dataX[i]);
			vo.setDataY(calcFitter(factors, dataX[i]));
			data.add(vo);
		}
		return data;
	}
	
	private List<DataVo> getDataFitter(double[] factors, List<DataVo> dataX) {
		List<DataVo> data = new ArrayList<DataVo>();
		for(DataVo dataVo: dataX) {
			DataVo vo = new DataVo();
			vo.setTimestamp(dataVo.getTimestamp());
			vo.setDataX(dataVo.getDataX());
			vo.setDataY(MeshMathUtil.setScale(2, calcFitter(factors, dataVo.getDataX())));
			data.add(vo);
		}
		return data;
	}

	@Override
	public List<SimulateEntity> listSimulate(ListSimulateMsg msg) throws BaseException {
		// TODO Auto-generated method stub
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getDatacenterId() != null) {
			props.put("datacenter_id",  msg.getDatacenterId());
		}
		if(msg.getMetricX() != null) {
			
			props.put("metricX", msg.getMetricX());
		}
		List<SimulateEntity> simulates = simulateDao.findByProperties(props);
		
		return simulateDao.findByProperties(props);
	}

	@Override
	public OptimumVo optimum(OptimumMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getDatacenterId() != null) {
			props.put("datacenter_id",  msg.getDatacenterId());
		}
		props.put("metricX", MeterXType.SERVER_POWER_CONSUMPTION.getName());
		List<SimulateEntity> simulates = simulateDao.findByProperties(props);

		double min = Double.MAX_VALUE;
		OptimumVo vo = new OptimumVo();
		for(SimulateEntity simulate: simulates) {
			
			if(simulate.getSimulateValue() == null || simulate.getSimulateValue() < 1 ) {
				continue;
			}
			if(simulate.getSimulateValue()!= null && simulate.getSimulateValue() < min) {	
				min = simulate.getSimulateValue();
				vo.setMetricX(simulate.getMetricX());
				vo.setMetricXCnName(MeterXType.getTypeByName(simulate.getMetricX()).getCnName());
				vo.setOptimalMetric(simulate.getSimulateMetric());
				vo.setOptimalValue(simulate.getSimulateValue());
				vo.setOptimalValueCnName("最优PUE");				
			}
			if(simulate.getSimulateValue()!= null && simulate.getSimulateValue() == min && simulate.getSimulateMetric() < vo.getOptimalMetric()) {	
				min = simulate.getSimulateValue();
				vo.setMetricX(simulate.getMetricX());
				vo.setMetricXCnName(MeterXType.getTypeByName(simulate.getMetricX()).getCnName());
				vo.setOptimalMetric(simulate.getSimulateMetric());
				vo.setOptimalValue(simulate.getSimulateValue());
				vo.setOptimalValueCnName("最优PUE");				
			}
		}
		return vo;
	}
	
	@Override
	public List<OptimumVo> listOptimum(ListOptimumMsg msg, String userId) throws BaseException {
		// TODO Auto-generated method stub
		Map<String, Object> props = new HashMap<String, Object>();
		if(msg.getDatacenterId() != null) {
			props.put("datacenter_id",  msg.getDatacenterId());
		}
		List<SimulateEntity> simulates = simulateDao.findByProperties(props);
		List<OptimumVo> optimums = new ArrayList<OptimumVo>();
		for(SimulateEntity simulate: simulates) {
			OptimumVo vo = new OptimumVo();
			vo.setMetricX(simulate.getMetricX());
			vo.setMetricXCnName(MeterXType.getTypeByName(simulate.getMetricX()).getCnName());
			vo.setOptimalMetric(simulate.getHistoryMetric());
			vo.setOptimalValue(simulate.getHistoryValue());
			vo.setOptimalValueCnName("最优PUE");
			
			optimums.add(vo);
		}
		return optimums;
	}

	@Override
	public PageResult<NodeHistoryVo> pageNodeHistory(int pageNum, int pageSize, String name, String userId)
			throws BaseException {
		// TODO Auto-generated method stub
		
		double minPue = 0;
//		if(demoEnable) {
//			List<SimulateEntity> simulates = simulateDao.findAll();
//			if(simulates.size() > 0 && simulates.get(0).getHistoryValue() != null) {
//				simulates.stream().filter(s -> s.getHistoryValue() != null && s.getHistoryValue() > 0).mapToDouble(s -> s.getHistoryValue()).min().getAsDouble();
//			}
//		}
		
		PageResult<NodeItemVo> nodes = null;
		try {
			nodes = assetService.pageNode(pageNum, pageSize, name, null, userId);
		}catch(Exception e) {
			log.info("[IntelligentDeviceService][pageNodeFitter] assetService的pageNode方法访问异常: {}", e.getMessage());
		}
		PageResult<NodeHistoryVo> result = new PageResult<NodeHistoryVo>();
		List<NodeHistoryVo> nodeHistory = new ArrayList<NodeHistoryVo>();
		if(nodes != null) {
			for(NodeItemVo nodeVo: nodes.getList()) {
				NodeHistoryVo vo = new NodeHistoryVo();	
				vo.setId(nodeVo.getId());
				vo.setName(nodeVo.getName());
				vo.setDatacenterId(nodeVo.getDatacenterId());
				vo.setRegion(nodeVo.getDatacenterName());
				vo.setIpmiIp(nodeVo.getIpmiIp());
				vo.setMgmIp(nodeVo.getMgmIp());
				vo.setPowerStatus(nodeVo.getPowerStatus());
				vo.setPowerStatusCnName(nodeVo.getPowerStatusCnName());
				vo.setPowerConsumption(Float.toString(nodeVo.getPowerConsumption()));
		
				try {
					vo.setPowerConsumption(dataCleaningService.getPwrNode(nodeVo.getId()));
				}catch(Exception e) {
					log.info("[IntelligentDeviceService][pageNodeFitter] DataCleaningService的getPwrNode方法访问异常: {}", e.getMessage());
				}
				Map<String, Object> props = new HashMap<String, Object>();
				props.put("device_id", nodeVo.getId());
				SimulateEntity simulate = simulateDao.findUniqueByProperties(props);
				if(simulate != null) {
					vo.setId(simulate.getId());
					vo.setHistoryMetric(simulate.getHistoryMetric());
					vo.setHistoryValue(simulate.getHistoryValue());
//					if(demoEnable && minPue > 0) {
//						vo.setHistoryValue(minPue);
//					}
				}
				
				nodeHistory.add(vo);
			}
		}

		result.setList(nodeHistory);
		result.setPageNo(pageNum);
		result.setPageSize(pageSize);
		if(nodes != null) {
			result.setTotalCount(nodes.getTotalCount());
		}
		
		
		return result;
	}

	@Override
	public PageResult<NodeSimulateVo> pageNodeSimulate(int pageNum, int pageSize, String name, String userId)
			throws BaseException {
		// TODO Auto-generated method stub
		
		double minPue = 0;
//		if(demoEnable) {
//			List<SimulateEntity> simulates = simulateDao.findAll();
//			if(simulates.size() > 0 && simulates.get(0).getSimulateValue() != null) {
//				simulates.stream().filter(s -> s.getSimulateValue() != null && s.getSimulateValue() > 0).mapToDouble(s -> s.getSimulateValue()).min().getAsDouble();
//			}
//		}

		PageResult<NodeSimulateVo> result = simulateDao.page(pageNum, pageSize, name, userId, NodeSimulateVo.class);
//		if(result.getList() != null) {
//			for(NodeSimulateVo vo: result.getList()) {
//				if(demoEnable && minPue > 0) {
//					vo.setSimulateValue(minPue);
//				}
//			}
//		}
		

		
//		if(demoEnable) {
//			for(NodeSimulateVo vo: result.getList()) {
//				if(vo.getSimulateMetric() == null || vo.getSimulateMetric() < 250) {
//					double metric = 250 + Math.random() * 200;
//					vo.setSimulateMetric(MeshMathUtil.setScale(2, metric));
//				}
//				if(vo.getSimulateValue() == null || vo.getSimulateValue() < 1) {
//					double value = 1.5 + Math.random() * 2;
//					vo.setSimulateValue(MeshMathUtil.setScale(2, value));
//				}
//			}
// 		}
		
		return result;
	}
	
	private IDataCleaning getDemoData(String type, String nodeId, String airId, Date startTime, Date endTime) {
		NodeItemVo node = assetService.detailNode(nodeId, null);
		DeviceItemVo device = assetService.detailDevice(airId, null);
		IDataCleaning result = new PolynomialDataCleaning();
		if(node != null && device != null && startTime != null) {
			List<Date> times = new ArrayList<Date>();
			times.add(node.getCreateTime());
			times.add(device.getCreateTime());
			times.add(startTime);
			String start = TimestampUtil.dateToStr(times.stream().max(Comparator.comparingLong(Date::getTime)).get());
			String end = TimestampUtil.dateToStr(endTime);
			List<DemoEntity> demoData = demoDao.list(type, start, end);
			List<DataVo> data = demoData
									.stream()
									.map( s -> {
											String timeStr = TimestampUtil.dateToStr(s.getTimestamp());
											String key = timeStr.substring(0, timeStr.length()-3);
											return new DataVo(key, MeshMathUtil.setScale(2, s.getDataX()), MeshMathUtil.setScale(2, s.getDataY()));
										}
									).collect(Collectors.toList());
			result.setData(data);
		}else {
			throw new BaseException("000000", "采集数据量不足，请稍后再试");
		}
		
		return result;
	}
	
	private IDataCleaning getDemoData(String type, String nodeId, Date startTime, Date endTime) {
		NodeItemVo node = assetService.detailNode(nodeId, null);
		IDataCleaning result = new PolynomialDataCleaning();
		if(node != null) {
			List<Date> times = new ArrayList<Date>();
			times.add(node.getCreateTime());
			times.add(startTime);
			String start = TimestampUtil.dateToStr(times.stream().max(Comparator.comparingLong(Date::getTime)).get());
			String end = TimestampUtil.dateToStr(endTime);
			List<DemoEntity> demoData = demoDao.list(type, start, end);
			List<DataVo> data = demoData
									.stream()
									.map( s -> {
											String timeStr = TimestampUtil.dateToStr(s.getTimestamp());
											String key = timeStr.substring(0, timeStr.length()-3);
											return new DataVo(key, MeshMathUtil.setScale(2, s.getDataX()), MeshMathUtil.setScale(2, s.getDataY()));
										}
									).collect(Collectors.toList());
			result.setData(data);
		}
		
		return result;
	}
	
	private IDataCleaning getDemoData(String type, Date startTime, Date endTime) {
		Map<String, Object> props = new HashMap<String, Object>();
		props.put("type", type);
		List<DemoEntity> demoData = demoDao.findByProperties(props);
		IDataCleaning result = new PolynomialDataCleaning();
		List<DataVo> data = demoData
								.stream()
								.map( s -> {
										String timeStr = TimestampUtil.dateToStr(s.getTimestamp());
										String key = timeStr.substring(0, timeStr.length()-3);
										return new DataVo(key, MeshMathUtil.setScale(2, s.getDataX()), MeshMathUtil.setScale(2, s.getDataY()));
									}
								).collect(Collectors.toList());
		result.setData(data);
		return result;
	}
	
	private double[] getFactors() {
		DemoEntity demo = demoDao.getFirst("simulate");
		double[] factors = FitterUtil.recalcFitterMode(demo.getResult());
		return factors;
	}
	
	private SimulateEntity saveSimulate(DoSimulateMsg msg) {
		SimulateEntity entity = new SimulateEntity();
		entity.setId(UUID.randomUUID().toString());
		entity.setDatacenterId(msg.getDatacenterId());
		entity.setDeviceId(msg.getDeviceId());
		entity.setDegree(msg.getDegree());
		entity.setMetricX(msg.getMetricX());
	
		simulateDao.save(entity);
		return entity;
		
	}
	
	private SimulateEntity updateSimulate(DoSimulateMsg msg, SimulateEntity entity) {
		if(msg.getDegree() != entity.getDegree()) {
			List<String> updates = new ArrayList<String>();
			updates.add("degree");
			entity.setDegree(msg.getDegree());
			simulateDao.update(entity, updates);
		}
		return entity;
		
	}
	
	private FitterEntity saveFitter(DoFitterMsg msg) {
		FitterEntity entity = new FitterEntity();
		entity.setId(UUID.randomUUID().toString());
		entity.setDegree(msg.getDegree());
		entity.setMetricX(msg.getMetricX());
		entity.setMetricY(msg.getMetricY());
		entity.setAirId(msg.getAirId());
		entity.setNodeId(msg.getNodeId());
	
		fitterDao.save(entity);
		return entity;
		
	}
	
	private FitterEntity updateFitter(DoFitterMsg msg, FitterEntity entity) {
		if(msg.getDegree() != entity.getDegree()) {
			List<String> updates = new ArrayList<String>();
			updates.add("degree");
			entity.setDegree(msg.getDegree());
			fitterDao.update(entity, updates);
		}
		return entity;
		
	}
	
	private void sorted(List<DataVo> list) {
		Collections.sort(list, new Comparator<DataVo>() {

			@Override
			public int compare(DataVo arg0, DataVo arg1) {
				// TODO Auto-generated method stub
				if(arg0.getDataY() > arg1.getDataY()) {
					return 1;
				}else {
					return -1;
				}
			}		
		});
	}
	
	private void simulateSorted(List<DataVo> list) {
		Collections.sort(list, new Comparator<DataVo>() {

			@Override
			public int compare(DataVo arg0, DataVo arg1) {
				// TODO Auto-generated method stub
				if(arg0.getDataX() > arg1.getDataX()) {
					return 1;
				}else {
					return -1;
				}
			}		
		});
	}
	
	private void updateHistorySimulateOptimum(String id, double historyM, double historyV, double simulateM, double simulateV) {
		
		SimulateEntity simulate = simulateDao.getById(id);
		List<String> updates = new ArrayList<String>();	
		if(simulate != null) {
			if(simulate.getHistoryValue() == null || (simulate.getHistoryValue() != null && simulate.getHistoryValue() > historyV)) {
				updates.add("history_metric");
				updates.add("history_value");
				simulate.setHistoryMetric(historyM);
				simulate.setHistoryValue(historyV);
			}
			
			if(simulate.getSimulateValue() == null || (simulate.getSimulateValue() != null && simulate.getSimulateValue() > historyV)) {
				updates.add("simulate_metric");
				updates.add("simulate_value");
				simulate.setHistoryMetric(historyM);
				simulate.setHistoryValue(historyV);
			}
		}

	}
	
	private void autoAdapterFactors(int degree, double[] factors) {
		switch(degree) {
			case 3: 
				factors[3] = factors[3] - 0.05*0.0000001;
				factors[2] = factors[2] + 0.1*0.0001;
				factors[1] = factors[1] + 0.05;
				factors[0] = factors[0] - 12.3;
				break;
			case 4: 
				factors[4] = factors[4] - 0.05*0.00000001;
				factors[3] = factors[3] + 0.0001*0.00001;
//				factors[2] = factors[2] + 0.05;
//				factors[1] = factors[1] + 0.05;
				factors[0] = factors[0] + 2;
				break;
			case 5: 
				factors[5] = factors[5] - 0.05*0.000000001;
				factors[4] = factors[4] + 0.00001*0.000001;
				factors[3] = factors[3] + 0.0001*0.00001;
//				factors[2] = factors[2] + 0.05;
//				factors[1] = factors[1] + 0.05;
//				factors[0] = factors[0] - 2178.5;
				break;
		}
		
	}
}
